SuperStrict

Import sidesign.minib3d
Import BaH.FreeImage

AppTitle = "oglLara by Ratchet V0.1"

Const MODEL_SCALE: Double = 10

Graphics3D(800, 600, 32, 2)
AntiAlias(4)

Global MousePress: Byte = False
Global showBones: Byte = False
Global showBoneNames: Byte = False
Global DataDir: String = "Data/"
Global ModelDir: String = "Juliet_LC_Purple_Pride/" '"Lollipop_LC/"
Global Font: TImageFont = LoadImageFont(DataDir  + "common/font.ttf", 8)

Global camerapivot: TPivot = CreatePivot()
Global camera: TCamera = CreateCamera(camerapivot)
PositionEntity(camera, 0, 10, -10)
CameraRange(camera, 0.1, 1000)
CameraClsColor(camera, 160, 140, 255)
PointEntity(camera, camerapivot)

Global plane: TMesh = CreateCube()
ScaleEntity(plane, 1000, 0.1, 1000)
Global planetexture: TTexture = LoadTexture(DataDir  + "common/ground/ground_diffuse.png")
EntityTexture(plane, planetexture)

Global light: TLight = CreateLight()
RotateEntity(light, 90, 0, 0)

Global model: TModel = LoadMeshAscii(DataDir + ModelDir + "generic_item.mesh.ascii")
ScaleEntity(model.pivot, MODEL_SCALE, MODEL_SCALE, MODEL_SCALE)
'PositionEntity(model.pivot, 10, 10, 10)
EntityParent(camerapivot, model.pivot)

Global pickedBone: TBoneEx

While Not KeyHit(KEY_ESCAPE)
	' control camera
	MoveEntity(camera,KeyDown(KEY_D)-KeyDown(KEY_A),0,KeyDown(KEY_W)-KeyDown(KEY_S))
	TurnEntity(camera,KeyDown(KEY_DOWN)-KeyDown(KEY_UP),KeyDown(KEY_LEFT)-KeyDown(KEY_RIGHT),0)
	If KeyHit(KEY_P) Then PointEntity(camera, model.pivot)
	If KeyHit(KEY_N) Then showBoneNames = Not showBoneNames
	If KeyHit(KEY_B) Then flipBones()
	If KeyHit(KEY_R) Then rotateBone(model.findMesh(pickedBone), pickedBone, 100, 100, 100) ; Print "ROTATING!"
	If MouseDown(MOUSE_LEFT) Then
		If MousePress Then
			If KeyDown(KEY_LCONTROL) Then
				'zoom
				MoveEntity(camera, 0, MouseYSpeed(), -MouseYSpeed())
			Else If KeyDown(KEY_LSHIFT) Then
				'move
				TranslateEntity(camera, MouseXSpeed(), -MouseYSpeed(), 0)
			Else
				'turn
				TurnEntity(camerapivot, MouseYSpeed(), -MouseXSpeed(), 0)
			End If			
		Else
			MousePress = True
			MouseYSpeed()
			MouseXSpeed()
		End If
	Else
		If MousePress Then
			MousePress = False
			pickBone()
		End If
	End If
	MoveEntity(camera, 0, -MouseZSpeed(), MouseZSpeed())
	UpdateBone2DCoords()
	
	RenderWorld
	BeginMax2D()
	DrawMax2D()
	EndMax2D()
	Flip
	Cls
Wend

Function LoadMeshAscii: TModel(url: String)
	Local model: TModel = New TModel
	Local mesh: TMesh
	Local surf: TSurface
	Local meshName: String
	Local renderGroup: Int
	Local texture: TTexture
	Local bone: TBoneEx
	Local boneName: String
	Local boneParent: Int
	Local file: TStream = ReadFile(url)
	Local i: Int
	Local j: Int
	Local k: Int
	Local pos: Int
	Local a: String[]
	Local boneCount: Int
	Local meshCount: Int
	Local uvLayerCount: Int
	Local textureCount: Int
	Local textureFilename: String
	Local textureUVLayerID: Int
	Local firstTexture: Byte = False
	Local vertexCount: Int
	Local vid: Int
	Local faceCount: Int
	Local boneCube: TMesh
	
	Function readCount: Int(file :TStream)
		Return ReadLine(file).Split(" ")[0].ToInt()
	End Function
	
	If Not file RuntimeError "could not open file " + url
	'bones
	boneCount = readCount(file)
	For i = 1 To boneCount
		boneName = ReadLine(file) 'name
		boneParent = readCount(file) 'parent
		a = ReadLine(file).Split(" ") 'x y z
		bone = model.addBone(boneParent, boneName, a[0].ToDouble(), a[1].ToDouble(), a[2].ToDouble())
		'create clickable joint/cube
		bone.joint = CreateCube(model.pivot)
		PositionEntity(bone.joint, bone.px, bone.py, -bone.pz)
		EntityColor(bone.joint, 128, 128, 128)
		ScaleEntity(bone.joint, 0.01, 0.01, 0.01)
		EntityAlpha(bone.joint, 0.5)
		EntityOrder(bone.joint, -1)
		EntityPickMode(bone.joint, 2)
	Next
	'meshes
	meshCount = readCount(file)
	For i = 1 To meshCount
		mesh = CreateMesh(model.pivot)
		model.meshes :+ [mesh]
		surf = CreateSurface(mesh)
		meshName = ReadLine(file) 'mesh name
		uvLayerCount = readCount(file) 'uv layer count
		For j = 1 To uvLayerCount
			'adduv layer
		Next
		'get render group from mesh name
		renderGroup = 1
		pos = meshName.Find("_")
		If pos > -1 Then
			If Int(meshName[..pos]) Then
				renderGroup = Int(meshName[..pos])
			End If
		End If
		
		'textures
		textureCount = readCount(file) 'texture count
		firstTexture = True
		For j = 1 To textureCount
			textureFilename = ReadLine(file)
			textureUVLayerID = readCount(file)
			texture = LoadTexture(DataDir + ModelDir + textureFilename, renderGroupToFlags(renderGroup))
			If texture Then
				If firstTexture = True Then
					firstTexture = False
					model.textures :+ [texture]
					EntityTexture(mesh, texture)
				End If
			End If
		Next
		
		'vertex
		vertexCount = readCount(file) 'vertex count
		For j = 1 To vertexCount
			a = ReadLine(file).Split(" ") 'x y z
			vid = AddVertex(surf, a[0].ToDouble(), a[1].ToDouble(), -a[2].ToDouble())
			a = ReadLine(file).Split(" ") 'nx ny nz
			VertexNormal(surf, vid, a[0].ToDouble(), a[1].ToDouble(), -a[2].ToDouble())
			a = ReadLine(file).Split(" ") 'r g b a
			VertexColor(surf, vid, a[0].ToInt(), a[1].ToInt(), a[2].ToInt(), a[3].ToInt())
			For k = 1 To uvLayerCount
				a = ReadLine(file).Split(" ") 'u v
				VertexTexCoords(surf, vid, a[0].ToDouble(), a[1].ToDouble())
			Next
			
			surf.vert_bone1_no = New Int[vertexCount]
			surf.vert_bone2_no = New Int[vertexCount]
			surf.vert_bone3_no = New Int[vertexCount]
			surf.vert_bone4_no = New Int[vertexCount]
			surf.vert_weight1 = New Float[vertexCount]
			surf.vert_weight2 = New Float[vertexCount]
			surf.vert_weight3 = New Float[vertexCount]
			surf.vert_weight4 = New Float[vertexCount]
			
			a = ReadLine(file).Split(" ") 'bone indices
			surf.vert_bone1_no[vid] = a[0].ToInt()
			surf.vert_bone2_no[vid] = a[1].ToInt()
			surf.vert_bone3_no[vid] = a[2].ToInt()
			surf.vert_bone4_no[vid] = a[3].ToInt()
			mesh.bones :+ [model.findBone(a[0].ToInt())]
			mesh.bones :+ [model.findBone(a[1].ToInt())]
			mesh.bones :+ [model.findBone(a[2].ToInt())]
			mesh.bones :+ [model.findBone(a[3].ToInt())]
		
			a = ReadLine(file).Split(" ") 'bone weights
			surf.vert_weight1[vid] = a[0].ToDouble()
			surf.vert_weight2[vid] = a[1].ToDouble()
			surf.vert_weight3[vid] = a[2].ToDouble()
			surf.vert_weight4[vid] = a[3].ToDouble()
		Next
		
		'faces
		faceCount = readCount(file) 'face count
		For j = 1 To faceCount
			a = ReadLine(file).Split(" ") 'indecies
			If faceCount = 1 Then
				AddTriangle(surf, 1, 2, 3)
			Else
				AddTriangle(surf, a[0].ToInt(), a[1].ToInt(), a[2].ToInt())
			End If
		Next
		TAnimation.NormaliseWeights(mesh)
		
		
		'prepare for animation
		mesh.anim = True
		mesh.anim_seqs_first[0] = 0
		mesh.anim_seqs_last[0] = 0
		For Local surf: TSurface = EachIn mesh.surf_list
		
			Local anim_surf: TSurface=New TSurface
			ListAddLast(mesh.anim_surf_list,anim_surf)
		
			anim_surf.no_verts=surf.no_verts
						
			anim_surf.vert_coords=surf.vert_coords[..]
		
			anim_surf.vert_bone1_no=anim_surf.vert_bone1_no[..surf.no_verts+1]
			anim_surf.vert_bone2_no=anim_surf.vert_bone2_no[..surf.no_verts+1]
			anim_surf.vert_bone3_no=anim_surf.vert_bone3_no[..surf.no_verts+1]
			anim_surf.vert_bone4_no=anim_surf.vert_bone4_no[..surf.no_verts+1]
			anim_surf.vert_weight1=anim_surf.vert_weight1[..surf.no_verts+1]
			anim_surf.vert_weight2=anim_surf.vert_weight2[..surf.no_verts+1]
			anim_surf.vert_weight3=anim_surf.vert_weight3[..surf.no_verts+1]
			anim_surf.vert_weight4=anim_surf.vert_weight4[..surf.no_verts+1]
			
			' transfer vmin/vmax values for using with TrimVerts func after
			anim_surf.vmin=surf.vmin
			anim_surf.vmax=surf.vmax
		
		Next
		
	Next
	CloseStream(file)
	
	Return model
End Function

Type TModel
	Field meshes: TMesh[]
	Field bones: TBoneEx[]
	Field textures: TTexture[]
	Field pivot: TPivot = CreatePivot()	
	
	Method addBone: TBoneEx(parent: Int = -1, name: String, px: Double, py: Double, pz: Double)
		Local bone: TBoneEx = New TBoneEx
		Local x: Float, y: Float, z: Float, w: Float
		Local pitch: Float, yaw: Float, roll: Float
		
		bone.name = name
		bone.px = px
		bone.py = py
		bone.pz = pz
		bone.n_px = px
		bone.n_py = py
		bone.n_pz = pz
		
		bone.qx = 0
		bone.qy = 0
		bone.qz = 0
		bone.n_qx = 0
		bone.n_qy = 0
		bone.n_qz = 0
		
		EulerToQuart(0,0,0,w,x,y,z)
		bone.rx = x
		bone.ry = y
		bone.rz = z
		bone.n_rx = x
		bone.n_ry = y
		bone.n_rz = z
		
		TQuaternion.QuatToMat(-bone.n_qw,bone.n_qx,bone.n_qy,-bone.n_qz,bone.mat)
		
		bone.mat.grid[3,0] = bone.n_px
		bone.mat.grid[3,1] = bone.n_py
		bone.mat.grid[3,2] = bone.n_pz
	
		If parent > -1 Then
			bone.AddParent(bones[parent])
		End If	
		
		If bone.parent<>Null And TBone(bone.parent)<>Null ' And... onwards needed to prevent inv_mat being incorrect if external parent supplied
			Local new_mat:TMatrix=bone.parent.mat.Copy()
			new_mat.Multiply(bone.mat)
			bone.mat.Overwrite(new_mat)
		EndIf

		bone.inv_mat=bone.mat.Inverse()
			
		bones :+ [bone]
	
		Return bone
	End Method
	
	Method findBone: TBone(i: Int)
		If (i >= 0) And (i < bones.Length) Then
			Return TBone(bones[i])
		Else
			Return Null
		End If
	End Method
	
	Method findMesh: TMesh(bone: TBone)
		Local result: TMesh = Null
	
		For Local m: TMesh = EachIn meshes
			For Local b: TBone = EachIn m.bones
				If b = bone Then
					result = m
					Exit
				End If
			Next
		Next
		
		Return result
	End Method
	
	Method kill()
		For Local m: TMesh = EachIn meshes
			FreeEntity(m)
		Next
		For Local t: TTexture = EachIn textures
			FreeTexture(t)
		Next
		FreeEntity(pivot)
	End Method
End Type

Type TBoneEx Extends TBone
	Field joint: TMesh
	Field projected_x: Double
	Field projected_y: Double
	Field projected_z: Double
	
	Method New()
		class = "Bone"
		keys = New TAnimationKeys
		keys.frames = 1
		keys.flags = New Int[1]
		keys.px = New Float[1]
		keys.py = New Float[1]
		keys.pz = New Float[1]
		keys.sx = New Float[1]
		keys.sy = New Float[1]
		keys.sz = New Float[1]
		keys.qw = New Float[1]
		keys.qx = New Float[1]
		keys.qy = New Float[1]
		keys.qz = New Float[1]
	End Method
End Type

Function flipBones()
	showBones = Not showBones
	For Local b: TBoneEx = EachIn model.bones
		If showBones Then
			ShowEntity(b.joint)
		Else
			HideEntity(b.joint)
		End If
	Next
End Function

Function UpdateBone2DCoords()
	For Local b: TBoneEx = EachIn model.bones
		CameraProject(camera, b.px * MODEL_SCALE, b.py * MODEL_SCALE, b.pz * MODEL_SCALE)
		b.projected_x = ProjectedX()
		b.projected_y = ProjectedY()
		b.projected_z = ProjectedZ()
	Next
End Function

Function DrawMax2D()
	SetImageFont(Font)
	SetBlend(ALPHABLEND)
	SetColor(255, 255, 255)
	'bone names
	If showBoneNames Then
		For Local b: TBoneEx = EachIn model.bones
			DrawText(b.name, b.projected_x - (TextWidth(b.name) / 2), b.projected_y)
		Next
	End If
End Function

Function pickBone()
	CameraPick(camera, MouseX(), MouseY())
	Local picked: TEntity = PickedEntity()
	If picked Then
		For Local b: TBoneEx = EachIn model.bones
			If b.joint = picked Then
				pickedBone = b
				EntityColor(b.joint, 255, 0, 0)
				EntityAlpha(b.joint, 1)
			Else
				EntityColor(b.joint, 128, 128, 128)
				EntityAlpha(b.joint, 0.5)
			End If
		Next
	End If
End Function

Function rotateBone(mesh: TMesh, bone: TBone, rx: Float, ry: Float, rz: Float)
	Local w:Float,x:Float,y:Float,z:Float
	Local pos: TVector = New TVector
	Local quat: TQuaternion = New TQuaternion
	
	mesh.anim = True	

	EulerToQuart(ry,rx,rz,w,x,y,z)
	
	pos.x = rx
	pos.y = ry
	pos.z = rz
	quat.x = x
	quat.y = y
	quat.z = z
	quat.w = w
	
	bone.keys.qw[0] = w
	bone.keys.qx[0] = x
	bone.keys.qy[0] = y
	bone.keys.qz[0] = z
	bone.keys.flags[0] = 5
	bone.keys.px[0] = bone.n_px#
	bone.keys.py[0] = bone.n_py#
	bone.keys.pz[0] = bone.n_pz#

	TAnimation.AnimateMesh(mesh, 0, 0, 0)
End Function

Function EulerToQuart(yaw:Float,pitch:Float,roll:Float,w:Float Var,x:Float Var,y:Float Var,z:Float Var)
	Local c1:Float = Cos(yaw/2),c2:Float=Cos(pitch/2),c3:Float = Cos(roll/2)
	Local s1:Float = Sin(yaw/2),s2:Float=Sin(pitch/2),s3:Float = Sin(roll/2)
	
	Local c1c2:Float = c1*c2 
	Local s1s2:Float = s1*s2
	
	w = (c1c2 * c3) - (s1s2 * s3)
	x = (c1c2 * s3) + (s1s2 * c3)
	y = (s1 * c2 * c3) + (c1* s2 * s3)
	z = (c1 * s2 * c3) - (s1 * c2 * s3)
End Function

Function renderGroupToFlags: Int(rg: Int)
	Return 1
End Function

Rem

RENDERGROUPS BY XNAaral (http://www.tombraiderforums.com/showpost.php?p=5254498&postcount=1735)

Group | Shading | Alpha | Poseable | Specular higlight | Bump1 repeater | bump2 repeater | Textures | Texture types                                            | Since | First model / mesh part     | Downloadlink
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1    | Yes     | No    | Yes      | Yes               | Yes            | Yes            | 6        | Diffuse, Lightmap, Bumpmap, Mask, Bump1, Bump2           | 1.0   | LaraJungleShorts / tshirt   | http://www.mediafire.com/?gc5cu5dtd2h
 2    | Yes     | No    | Yes      | Yes               | No             | No             | 3        | Diffuse, Lightmap, Bumpmap                               | 1.0   | LaraJungleShorts / face     | http://www.mediafire.com/?gc5cu5dtd2h
 3    | Yes     | No    | Yes      | No                | No             | No             | 2        | Diffuse, Lightmap                                        | 1.0   | LaraJungleShorts / backring | http://www.mediafire.com/?gc5cu5dtd2h
 4    | Yes     | No    | Yes      | Yes               | No             | No             | 2        | Diffuse, Bumpmap                                         | 1.0   | LaraJungleShorts / metal    | http://www.mediafire.com/?gc5cu5dtd2h
 5    | Yes     | No    | Yes      | No                | No             | No             | 1        | Diffuse                                                  | 1.0   | LaraJungleShorts / eyewhites| http://www.mediafire.com/?gc5cu5dtd2h
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6    | Yes     | Yes   | Yes      | Yes               | No             | No             | 2        | Diffuse, Bumpmap                                         | 1.0   | LaraJungleShorts / hair2    | http://www.mediafire.com/?gc5cu5dtd2h
 7    | Yes     | Yes   | Yes      | No                | No             | No             | 1        | Diffuse                                                  | 1.0   | LaraJungleShorts / eyelashes| http://www.mediafire.com/?gc5cu5dtd2h
 8    | Yes     | Yes   | Yes      | Yes               | No             | No             | 3        | Diffuse, Lightmap, Bumpmap                               | 1.8   | Natla / hair4               | http://www.mediafire.com/?4wmzyzxwj5y
 9    | Yes     | Yes   | Yes      | No                | No             | No             | 2        | Diffuse, Lightmap                                        | 1.8   | Natla / hair5               | http://www.mediafire.com/?4wmzyzxwj5y
10    | No      | No    | Yes      | No                | No             | No             | 1        | Diffuse                                                  | 1.85  | Doppelganger / eyepupils    | http://www.mediafire.com/?m0q9yctdris
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
11    | Vertex  | No    | No       | Yes               | No             | No             | 2        | Diffuse, Bumpmap                                         | 4.1   | CroftManorHall / Group1     | http://www.mediafire.com/?jlt33lalmjj
12    | Vertex  | Yes   | No       | Yes               | No             | No             | 2        | Diffuse, Bumpmap                                         | 4.1   | CroftManorHall / Group35    | http://www.mediafire.com/?jlt33lalmjj
13    | No      | No    | No       | No                | No             | No             | 1        | Diffuse                                                  | 4.1   | CroftManorHall / Group91    | http://www.mediafire.com/?jlt33lalmjj
14    | No      | No    | No       | Yes               | No             | No             | 2        | Diffuse, Bumpmap                                         | 4.2   | CroftManorHallLQ / Group1   | http://www.mediafire.com/?zjeznnzcgaz
15    | No      | Yes   | No       | Yes               | No             | No             | 2        | Diffuse, Bumpmap                                         | 4.2   | CroftManorHallLQ / Group35  | http://www.mediafire.com/?zjeznnzcgaz
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
16    | Yes     | No    | No       | No                | No             | No             | 1        | Diffuse                                                  | 4.7   | Yacht / part1               | http://www.mediafire.com/?mwakzzz1djy
17    | Yes     | No    | No       | No                | No             | No             | 2        | Diffuse, Lightmap                                        | 4.7   | Yacht / part5               | http://www.mediafire.com/?mwakzzz1djy
18    | Yes     | Yes   | No       | No                | No             | No             | 1        | Diffuse                                                  | 4.7   | Yacht / part13              | http://www.mediafire.com/?mwakzzz1djy
19    | Yes     | Yes   | No       | No                | No             | No             | 2        | Diffuse, Lightmap                                        | 5.6   | ShipNatlaRoom / Mesh005     | http://www.mediafire.com/?ztjozjnninn
20    | Yes     | Yes   | Yes      | Yes               | Yes            | Yes            | 6        | Diffuse, Lightmap, Bumpmap, Mask, Bump1, Bump2           | 7.8   | KnightThrall / Mesh001      | http://www.mediafire.com/?z4uwig2dzum
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
21    | No      | Yes   | Yes      | No                | No             | No             | 1        | Diffuse                                                  | 9.1   | kerrigan / $AtlantiB$       | 
22    | Yes     | No    | Yes      | Yes               | Yes            | Yes            | 7        | Diffuse, Lightmap, Bumpmap, Mask, Bump1, Bump2, Specular | 9.3   | ICE-7E / suit               | http://www.mediafire.com/?leipjbpmeyn2w2p
23    | Yes     | Yes   | Yes      | Yes               | Yes            | Yes            | 7        | Diffuse, Lightmap, Bumpmap, Mask, Bump1, Bump2, Specular | 9.3   | ICE-7E / ice                | http://www.mediafire.com/?leipjbpmeyn2w2p
24    | Yes     | No    | Yes      | Yes               | No             | No             | 4        | Diffuse, Lightmap, Bumpmap, Specular                     | 9.42  |
25    | Yes     | Yes   | Yes      | Yes               | No             | No             | 4        | Diffuse, Lightmap, Bumpmap, Specular                     | 9.42  | 
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
26    | YES/No  | No    | Yes      | Yes intensity     | No             | No             | 3        | Diffuse, Bumpmap, enviroment                             | 9.5   | MetallicExample / trousers1 | http://www.mediafire.com/?g8gah73w0mv45q7
27    | YES/No  | Yes   | Yes      | Yes intensity     | No             | No             | 3        | Diffuse, Bumpmap, enviroment                             | 9.5.5 |
28    | YES/No  | No    | Yes      | Yes intensity     | YES            | YES            | 6        | Diffuse, Bumpmap, Mask, Bump1, Bump2, enviroment         | 9.6   |
29    | YES/No  | Yes   | Yes      | Yes intensity     | YES            | YES            | 6        | Diffuse, Bumpmap, Mask, Bump1, Bump2, enviroment         | 9.6   |
endrem